#include <ostream.h>
#include <istream.h>
#include "multiboot.h"
#include <asmf.h>
#include <gdt.h>
#include <idt.h>
#include <isrs.h>
#include <_null.h>
#include <irq.h>
#include <timer.h>
#include <common.h>
#include <keyboard.h>
#include <size_t.h>
#include <string.h>
#include <stdint.h>
#include <paging.h>

#define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))

using namespace std;

extern "C" int main( int magic, char** addr);

int main( int  magic, char** addr)
{
	multiboot_info_t *mbi;
	
	/* Clear the screen. */
	cout.clear();
	
	/* Am I booted by a Multiboot-compliant boot loader? */
	if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
	{
		cout << "Invalid magic number: 0x" << (unsigned) magic << endl;
		return 1;
	}
	
	/* Set MBI to the address of the Multiboot information structure. */
	mbi = (multiboot_info_t *) addr;
	
	cout << "Checking Memory.... ";
	
	/* Are mem_* valid? */
	if (CHECK_FLAG (mbi->flags, 0))
		cout << "[DONE]" << endl;
	else {
		cout << "No Memory Availible! Cannot Continue...." << endl;
		return 1;
	}

	
	cout << "Checking Boot Device.... ";
	
	/* Is boot_device valid? */
	if (CHECK_FLAG (mbi->flags, 1))
		cout << "[DONE]" << endl;
	else {
		cout << "Not valid boot Device.... Cannot Continue...." << endl;
		return 1;
	}
	
	/* Is the command line passed? */
	if (CHECK_FLAG (mbi->flags, 2))
		cout << "Command Line.... " << (char *) mbi->cmdline << endl;
	
	/* Are mods_* valid? */
	if (CHECK_FLAG (mbi->flags, 3))
	{
		module_t *mod;
		int i;
		
		cout << "Number Of Mods.... " << (int) mbi->mods_count << endl << "Starting Address Of Mods.... 0x" << (int) mbi->mods_addr << endl;
		for (i = 0, mod = (module_t *) mbi->mods_addr;
			 i < mbi->mods_count;
			 i++, mod++)
			cout << "Mod Start... 0x" << (unsigned) mod->mod_start << endl << "Mod End.... 0x" << (unsigned) mod->mod_end << endl << "Name.... " << (char *) mod->string << endl;
	}
	
	/* Bits 4 and 5 are mutually exclusive! */
	if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5))
	{
		cout << "Both bits 4 and 5 are set." << endl;
		return 1;
	}
	
	/* Is the symbol table of a.out valid? */
	if (CHECK_FLAG (mbi->flags, 4))
	{
		aout_symbol_table_t *aout_sym = &(mbi->u.aout_sym);
		
		cout << "Aout System Table:\n    Table Size.... 0x" << (unsigned) aout_sym->tabsize << "\n    String Size.... 0x" << (unsigned) aout_sym->strsize << "\n    Address.... 0x" << (unsigned) aout_sym->addr << endl;
	}
	
	/* Is the section header table of ELF valid? */
	if (CHECK_FLAG (mbi->flags, 5))
	{
		elf_section_header_table_t *elf_sec = &(mbi->u.elf_sec);
		
		cout << "Elf Section Header Table:\n    Number.... " << (unsigned) elf_sec->num << "\n    Size.... 0x" << (unsigned) elf_sec->size << "\n    Address.... 0x" << (unsigned) elf_sec->addr << "\n    SHNDX.... 0x" << (unsigned) elf_sec->shndx;
	}
	
	/* Are mmap_* valid? */
	if (CHECK_FLAG (mbi->flags, 6))
	{
		memory_map_t *mmap;
		
		cout << "mmap_addr = 0x" << (unsigned) mbi->mmap_addr << ", mmap_length = 0x" << (unsigned) mbi->mmap_length << endl;
		
		for (mmap = (memory_map_t *) mbi->mmap_addr;
			 (long) mmap < mbi->mmap_addr + mbi->mmap_length;
			 mmap = (memory_map_t *) ((unsigned long) mmap
									  + mmap->size + sizeof (mmap->size)))
			cout << " size = 0x" << (unsigned) mmap->size << ", base_addr = 0x" << (unsigned) mmap->base_addr_high << (unsigned) mmap->base_addr_low << " length = 0x" << (unsigned) mmap->length_high << (unsigned) mmap->length_low << ", type = 0x" << (unsigned) mmap->type << endl;
	}
	
	cout << "Installing GDT.... ";
	gdt_install();
	cout << "[DONE]" << endl;
	cout << "Installing IDT.... ";
	idt_install();
	cout << "[DONE]" << endl;
	cout << "Installing ISRs.... ";
	isrs_install();
	cout << "[DONE]" << endl;
	cout << "Installing IRQs.... ";
	irq_install();
	cout << "[DONE]" << endl;
	cout << "Enabling Interrupts.... ";
	asm volatile ("sti");
	cout << "[DONE]" << endl;
	cout << "Installing Timer.... ";
	timer_install();
	cout << "[DONE]" << endl;
	cout << "Installing Keyboard Handler! ";
	kkybrd_install(1);
	cout << "[DONE]" << endl;
	cout << "Enabling Paging! ";
	enable_paging();
	cout << "[DONE]" << endl;
	
	cout << endl << "Welcome To FrostOS" << endl;
	
	string command;
	cout << endl;
	while (true)
	{
		cout << ":>";
		cin >> command;
		
		cout << "Unknown Command" << endl;
		if (error == true)
		{
			cout << "An Unknown Error has Occured Please use the Power Button To Reset the Machine";
			break;
		}
	}
	for(;;);
	return 0;
	cout << "Did not return..... Please Use Power Button To Shutoff Computer!" << endl;
}
